#include <glib.h>
#include <stdio.h>
#include <string.h>
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
#include "parser.h"

#define XML_ENCODING "ISO-8859-1"
xmlChar *ConvertInput(const char *in, const char *encoding);

void cb(Parser* parser, int type, const char* c, void* data)
{
  int      rc  = 0;
  xmlChar* tmp = NULL;
  xmlTextWriterPtr writer = (xmlTextWriterPtr)data;
  //printf("%i: %s\n", type, c);
  fprintf(stderr, "\b\b\b\b\b\b\b%6.2f%%", parser_get_progress(parser) * 100);
  switch (type) {
    case T_OPEN:
      rc = xmlTextWriterStartElement(writer, BAD_CAST c);
      break;

    case T_CLOSE:
      rc = xmlTextWriterEndElement(writer);
      break;

    case T_SINGLE:
      rc = xmlTextWriterStartElement(writer, BAD_CAST c);
      if (rc >= 0)
        rc = xmlTextWriterEndElement(writer);
      break;

    case T_DATA:
    case T_DATA_APPEND:
      tmp = ConvertInput(c, XML_ENCODING);
      rc  = xmlTextWriterWriteElement(writer, BAD_CAST "NAME_1", tmp);
      if (tmp != NULL)
        xmlFree(tmp);
      break;

    default:
      g_error("Invalid type");
  }
  if (rc < 0) {
    fprintf(stderr, "Error at xmlTextWriterStartElement\n");
    return;
  }
}


/**
 * ConvertInput:
 * @in: string in a given encoding
 * @encoding: the encoding used
 *
 * Converts @in into UTF-8 for processing with libxml2 APIs
 *
 * Returns the converted UTF-8 string, or NULL in case of error.
 */
xmlChar *
ConvertInput(const char *in, const char *encoding)
{
  xmlChar *out;
  int ret;
  int size;
  int out_size;
  int temp;
  xmlCharEncodingHandlerPtr handler;

  if (in == 0)
    return 0;

  handler = xmlFindCharEncodingHandler(encoding);

  if (!handler) {
    printf("ConvertInput: no encoding handler found for '%s'\n",
           encoding ? encoding : "");
    return 0;
  }

  size = (int) strlen(in) + 1;
  out_size = size * 2 - 1;
  out = (unsigned char *) xmlMalloc((size_t) out_size);

  if (out != 0) {
    temp = size - 1;
    ret = handler->input(out, &out_size, (const xmlChar *) in, &temp);
    if ((ret < 0) || (temp - size + 1)) {
      if (ret < 0) {
        printf("ConvertInput: conversion wasn't successful.\n");
      } else {
        printf("ConvertInput: conversion wasn't successful. converted: %i octets.\n", temp);
      }

      xmlFree(out);
      out = 0;
    } else {
      out = (unsigned char *) xmlRealloc(out, out_size + 1);
      out[out_size] = 0;  /*null terminating out */
    }
  } else {
    printf("ConvertInput: no mem\n");
  }

  return out;
}


int main(int argc, const char** argv)
{
  Parser* parser  = NULL;
  gsize   size    = 0;
  gchar*  content = NULL;
  int     rc      = 0;
  xmlTextWriterPtr writer;

  if (argc != 2) {
    fprintf(stderr, "Syntax: %s filename\n", argv[0]);
    return 1;
  }

  fprintf(stderr, "Reading file %s...\n", argv[1]);
  if (!g_file_get_contents(argv[1], &content, &size, NULL)) {
    fprintf(stderr, "Error: Cannot read %s. Check file permissions?\n", argv[1]);
    return 1;
  }

  /*
   * this initialize the library and check potential ABI mismatches
   * between the version it was compiled for and the actual shared
   * library used.
   */
  fprintf(stderr, "Initializing XML library... ");
  LIBXML_TEST_VERSION
  writer = xmlNewTextWriterFilename("/dev/stdout", 0);
  if (writer == NULL) {
    fprintf(stderr, "Error creating the xml writer.\n");
    return 1;
  }
  fprintf(stderr, "done.\n");

  rc = xmlTextWriterStartDocument(writer, NULL, XML_ENCODING, NULL);
  if (rc < 0) {
    fprintf(stderr, "Error at xmlTextWriterStartDocument\n");
    return 1;
  }

  rc = xmlTextWriterStartElement(writer, BAD_CAST "xml");
  if (rc < 0) {
    fprintf(stderr, "Error at xmlTextWriterStartElement\n");
    return 1;
  }

  fprintf(stderr, "Initializing parser... ");
  parser = parser_new();
  fprintf(stderr, "done.\n");

  fprintf(stderr, "Parsing...    0.00%%");
  if (parser_run(parser, content, cb, (void*)writer) != 0) {
    fprintf(stderr, "Error: Parser failed: %s\n", parser_error(parser));
    return 1;
  }
  fprintf(stderr, "\b\b\b\b\b\b\b%6.2f%%\n", parser_get_progress(parser) * 100);

  parser_free(parser);

  fprintf(stderr, "Completing XML... ");
  rc = xmlTextWriterEndDocument(writer);
  if (rc < 0) {
    fprintf(stderr, "Error at xmlTextWriterEndDocument\n");
    return 1;
  }
  fprintf(stderr, "done.\n");

  /*
   * Cleanup function for the XML library.
   */
  xmlFreeTextWriter(writer);
  xmlCleanupParser();
  /*
   * this is to debug memory for regression tests
   */
  xmlMemoryDump();
  return 0;
}
